<template>
  <MainLayout :overlay="loadingAccounts">
    <template #actions>
      <NavbarSeparator class="hidden lg:block" />

      <div class="inline-flex items-center">
        <IMinimalDropdown
          type="horizontal"
          :placement="
            !(account.is_initial_sync_performed && !isSyncDisabled)
              ? 'bottom-end'
              : 'bottom'
          "
        >
          <IDropdownItem
            v-if="account.authorizations.update"
            :to="{
              name: `edit-email-account`,
              params: { id: account.id },
            }"
            :text="$t('mailclient::mail.account.edit')"
          />

          <IDropdownItem
            :to="{ name: 'email-accounts-index' }"
            :text="$t('mailclient::mail.account.manage')"
          />
        </IMinimalDropdown>

        <IButton
          v-if="account.is_initial_sync_performed && !isSyncDisabled"
          v-i-tooltip.left="$t('mailclient::inbox.synchronize')"
          variant="secondary"
          size="sm"
          class="ml-3 lg:ml-6"
          :disabled="syncInProgress"
          :loading="syncInProgress"
          icon="Refresh"
          @click="performCurrentAccountManualSync"
        />
      </div>
    </template>

    <div class="mx-auto max-w-7xl">
      <div
        v-if="!loadingAccounts && hasAccounts"
        class="grid grid-cols-12 gap-4"
      >
        <div class="col-span-12 lg:col-span-3">
          <div class="sm:sticky sm:top-2">
            <IDropdownSelect
              adaptive-width
              :items="accounts"
              :model-value="account"
              class="w-full"
              label-key="display_email"
              @change="handleAccountSelected"
            >
              <template #default="{ label, toggle }">
                <IButton
                  variant="white"
                  class="justify-between py-2.5"
                  :loading="syncInProgress"
                  block
                  @click="toggle"
                >
                  <span class="truncate font-medium">{{ label }}</span>

                  <Icon
                    icon="ChevronDown"
                    class="-mr-1 ml-2 h-5 w-5 shrink-0"
                  />
                </IButton>
              </template>
            </IDropdownSelect>

            <IButton
              variant="primary"
              class="my-3"
              block
              icon="Mail"
              :disabled="!account.can_send_mails"
              :text="$t('mailclient::mail.compose')"
              @click="compose(true)"
            />

            <FoldersMenu :folders="account && account.active_folders_tree" />

            <ul
              v-if="availableTags.length"
              class="mt-10 flex flex-1 flex-col gap-y-3"
            >
              <li
                class="text-sm font-semibold leading-6 text-neutral-700 dark:text-neutral-300"
              >
                {{ $t('core::tags.tags') }} ({{ availableTags.length }})
              </li>

              <li v-for="tag in availableTags" :key="tag.id">
                <RouterLink
                  class="flex items-center space-x-2 rounded-md px-3 py-1 text-sm font-medium leading-6 text-neutral-700 hover:bg-neutral-200/50 focus:outline-none dark:text-neutral-100 dark:hover:dark:bg-neutral-700"
                  :class="
                    $route.query.tag == tag.name
                      ? 'bg-neutral-200/50 dark:bg-neutral-700'
                      : ''
                  "
                  :to="{
                    query: {
                      tag: tag.name,
                    },
                  }"
                >
                  <Icon
                    icon="Tag"
                    class="h-4 w-4"
                    :style="{ color: tag.swatch_color }"
                  />

                  <span class="grow" v-text="tag.name" />

                  <IButtonIcon
                    v-if="$route.query.tag == tag.name"
                    icon="X"
                    @click.prevent.stop="
                      $router.replace({
                        query: {
                          ...$route.query,
                          tag: undefined,
                        },
                      })
                    "
                  />
                </RouterLink>
              </li>
            </ul>
          </div>
        </div>

        <div class="col-span-12 lg:col-span-9">
          <InboxMessagesWarnings
            :account="account"
            :total-accounts="accounts.length"
            :has-primary-account="hasPrimaryAccount"
            :is-sync-disabled="isSyncDisabled"
          />

          <IAlert
            v-if="!account.is_initial_sync_performed"
            class="mb-4 border border-info-200"
          >
            {{ $t('mailclient::mail.initial_sync_info') }}
          </IAlert>

          <RouterView name="message" :account="account" />

          <RouterView
            v-if="hasActiveFolders"
            ref="messages"
            name="messages"
            :account="account"
          />

          <div v-else class="h-60">
            <div class="mx-auto mt-8 block max-w-2xl text-center">
              <Icon icon="Folder" class="mx-auto h-12 w-12 text-neutral-400" />

              <p
                v-t="'mailclient.mail.account.no_active_folders'"
                class="mt-1 text-sm text-neutral-600 dark:text-neutral-200"
              />

              <div class="mt-6 space-x-6">
                <RouterLink
                  v-if="account.authorizations.update"
                  class="link text-sm"
                  :to="{
                    name: 'edit-email-account',
                    params: { id: account.id },
                  }"
                >
                  {{ $t('mailclient::mail.account.activate_folders') }}
                  <span aria-hidden="true">&rarr;</span>
                </RouterLink>

                <RouterLink
                  :to="{ name: 'email-accounts-index' }"
                  class="link text-sm"
                >
                  {{ $t('mailclient::mail.account.manage') }}
                  <span aria-hidden="true">&rarr;</span>
                </RouterLink>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>

    <ComposeMessage
      :visible="isComposing"
      :default-account="account"
      @modal-hidden="compose(false)"
    />
  </MainLayout>
</template>

<script setup>
import { computed, ref, watch } from 'vue'
import { onBeforeRouteUpdate, useRoute, useRouter } from 'vue-router'
import { useStore } from 'vuex'

import {
  emitGlobal,
  useGlobalEventListener,
} from '@/Core/composables/useGlobalEventListener'

import { useMessageTags } from '../../composables/useMessageTags'
import ComposeMessage from '../Emails/ComposeMessage.vue'

import FoldersMenu from './InboxMessagesFoldersMenu.vue'
import InboxMessagesWarnings from './InboxMessagesWarnings.vue'

const route = useRoute()
const router = useRouter()
const store = useStore()

const loadingAccounts = ref(true)
const isComposing = ref(false)

const { availableTags } = useMessageTags()

watch(
  () => route.query.compose,
  newVal => {
    newVal && compose()
  }
)

// When viewing a message and click on a tag located in the left menu
// it should navigate away from the message and show the table filtered by the selected tag.
watch(
  () => route.query.tag,
  newVal => {
    if (newVal && route.params.id) {
      router.push({
        name: 'inbox-messages',
        account_id: route.params.accountId,
        folderId: route.params.folderId,
        query: {
          ...route.query,
          tag: newVal,
        },
      })
    }
  }
)

/**
 * When navigating e.q. from message and directly clicking
 * on the MENU item INBOX, we need to trigger the initAccounts methods
 * as the accounts are not loaded nor redirecting to the messages route
 */
onBeforeRouteUpdate((to, from, next) => {
  if (to.name === 'inbox') {
    redirectToAccountMessages(account.value, to.query)
  } else {
    next()
  }
})

const accounts = computed(() => store.getters['emailAccounts/accounts'])

const hasPrimaryAccount = computed(
  () => store.getters['emailAccounts/hasPrimary']
)

const hasAccounts = computed(() => accounts.value.length > 0)

const account = computed(
  () => store.getters['emailAccounts/activeInboxAccount']
)

const syncInProgress = computed(() => store.state.emailAccounts.syncInProgress)

const hasActiveFolders = computed(() => account.value.active_folders.length > 0)

const isSyncDisabled = computed(
  () => account.value.is_sync_stopped || account.value.is_sync_disabled
)

function setActiveAccount(account) {
  store.commit('emailAccounts/SET_INBOX_ACCOUNT', account)
}

function updateAccountInStore(data) {
  store.commit('emailAccounts/UPDATE', data)
}

function fetchAccounts(data) {
  return store.dispatch('emailAccounts/fetch', data)
}

function syncAccount(accountId) {
  return store.dispatch('emailAccounts/syncAccount', accountId)
}

function compose(boolean = true) {
  isComposing.value = boolean

  if (boolean == false) {
    let query = Object.assign({}, route.query)
    delete query.compose
    router.replace({ query })
  }
}

function handleAccountSelected(account) {
  setActiveAccount(account)
  redirectToAccountMessages(account)
}

function handleActionExecutedEvent(action) {
  // Makes sure to update the account after an action is executed
  // This will be update data like the folders unread count
  if (Object.hasOwn(action.response, 'account')) {
    store.commit('emailAccounts/UPDATE', {
      id: action.response.account.id,
      item: action.response.account,
    })
  }

  // Update global unread messages count
  if (Object.hasOwn(action.response, 'unread_count')) {
    store.dispatch(
      'emailAccounts/updateUnreadCountUI',
      action.response.unread_count
    )
  }
}

function redirectToAccountMessages(forAccount, query = {}) {
  let folderId = forAccount.active_folders[0]
    ? forAccount.active_folders[0].id
    : null

  // When account does not have active folders
  if (!folderId) {
    return
  }

  router.replace({
    name: 'inbox-messages',
    params: {
      account_id: forAccount.id,
      // Sets the first syncable folder as default
      folder_id: folderId,
    },
    query: { ...route.query, ...query },
  })
}

function handleSyncFinishedEvent() {
  initAccounts(true)
}

async function initAccounts(skipCache = false) {
  await fetchAccounts({
    force: skipCache,
  })

  if (!hasAccounts.value) {
    router.replace({
      name: 'email-accounts-index',
    })

    return
  }

  // Check if the account is configured when handleSyncFinishedEvent method calls this function
  if (route.params.account_id && route.params.folder_id) {
    setActiveAccount(parseInt(route.params.account_id))
  } else if (Object.keys(account.value).length === 0) {
    setActiveAccount(accounts.value[0])
  }

  // When accessing the INBOX route without any params
  // Redirect to the messages
  if (route.name === 'inbox' && hasActiveFolders.value) {
    redirectToAccountMessages(account.value)
  }
}

function performCurrentAccountManualSync() {
  syncAccount(account.value.id).then(data => {
    // Update the account in store in case of folder changes
    updateAccountInStore({ id: data.id, item: data })

    emitGlobal('user-synchronized-email-account', data)
  })
}

initAccounts()
  .then(() => route.query.compose && compose())
  .finally(() => (loadingAccounts.value = false))

useGlobalEventListener('action-executed', handleActionExecutedEvent)
useGlobalEventListener('email-accounts-sync-finished', handleSyncFinishedEvent)
</script>
